package com.hejjon.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hejjon.core.constant.SysConstants;
import com.hejjon.core.domain.entity.SysMenu;
import com.hejjon.core.domain.vo.MenuVO;
import com.hejjon.core.enumer.DeleteFlagEnum;
import com.hejjon.core.exception.BusinessException;
import com.hejjon.core.utils.DateTimeUtil;
import com.hejjon.core.utils.StrUtil;
import com.hejjon.domain.dto.SystemMenuDTO;
import com.hejjon.mapper.SysMenuMapper;
import com.hejjon.service.ISysMenuService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: cs
 * @date: 2024-12-20 12:38:42
 * @since: 1.0
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {


    @Resource
    private SysMenuMapper sysMenuMapper;

    @Override
    public boolean checkNameAndTextUnique(String menuName, String menuText) {
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysMenu::getName, menuName).or().eq(SysMenu::getText, menuText);
        wrapper.eq(SysMenu::getDeleteFlag, DeleteFlagEnum.NO.getCode());
        Long count = sysMenuMapper.selectCount(wrapper);
        return count == 0;
    }

    @Override
    public int add(SysMenu sysMenu) {
        sysMenu.setId(StrUtil.getUUID());
        sysMenu.setCreateTime(LocalDateTime.now());
        sysMenu.setCreateBy("admin");
        sysMenu.setDeleteFlag( DeleteFlagEnum.NO.getCode());
        int maxOrderNum = sysMenuMapper.selectMaxOrderNumByLocation(sysMenu.getLocation());
        sysMenu.setOrderNum(maxOrderNum + 1);
        return sysMenuMapper.insert(sysMenu);
    }


    @Override
    public List<MenuVO> findTopNavMenuList() {

        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysMenu::getLocation, SysConstants.MENU_LOCATION_TOP);
        wrapper.orderBy(true, true, SysMenu::getOrderNum);
        wrapper.eq(SysMenu::getDeleteFlag, DeleteFlagEnum.NO.getCode());
        List<SysMenu> sysMenus = sysMenuMapper.selectList(wrapper);
        List<MenuVO> voList = new ArrayList<>();

        for (SysMenu sysMenu : sysMenus) {
            MenuVO vo = convert2MenVO(sysMenu);
            voList.add(vo);
        }

        return voList;
    }

    @Override
    public List<MenuVO> findNavMenuList(SystemMenuDTO dto) {
        return sysMenuMapper.selectBy(dto);
    }

    @Override
    public List<MenuVO> findSubMenusByParentId(String parentId) {

        List<SysMenu> sysMenus = super.list();
        List<MenuVO> voList = new ArrayList<>();
        for (SysMenu sysMenu : sysMenus) {
            MenuVO vo = convert2MenVO(sysMenu);
            voList.add(vo);
        }

        return voList.stream()
                .peek(v -> v.setChildren(getChildren(v, voList)))
                .sorted(Comparator.comparingInt(SysMenu::getOrderNum))
                .filter(vo -> vo.getParentId().equals(parentId))
                .collect(Collectors.toList());
    }


    private MenuVO convert2MenVO(SysMenu sysMenu) {
        MenuVO vo = new MenuVO();
        vo.setId(sysMenu.getId());
        vo.setName(sysMenu.getName());
        vo.setText(sysMenu.getText());
        vo.setType(sysMenu.getType());
        vo.setLocation(sysMenu.getLocation());
        vo.setDescription(sysMenu.getDescription());
        vo.setDefaultActive(sysMenu.getDefaultActive());
        vo.setCreateTime(sysMenu.getCreateTime());
        vo.setCreateBy(sysMenu.getCreateBy());
        LocalDateTime time = sysMenu.getUpdateTime() != null ? sysMenu.getUpdateTime() : sysMenu.getCreateTime();
        String lastModifyTime = DateTimeUtil.localDateTime2Str(time);
        vo.setLastModifyTime(lastModifyTime);
        vo.setLastModifyUser(sysMenu.getUpdateBy() != null ? sysMenu.getUpdateBy() : sysMenu.getCreateBy());
        vo.setPath(sysMenu.getPath());
        vo.setOrderNum(sysMenu.getOrderNum());
        vo.setParentId(sysMenu.getParentId());
        return vo;
    }


    private static List<MenuVO> getChildren(MenuVO root, List<MenuVO> all) {
        return all.stream()
                .filter(vo -> root.getId().equals(vo.getParentId()))
                .peek(vo -> {
                    vo.setChildren(getChildren(vo, all));
                })
                .sorted(Comparator.comparingInt(SysMenu::getOrderNum))
                .collect(Collectors.toList());
    }


    @Override
    public Map<String, List<MenuVO>> getMunuData() {

        List<SysMenu> topMenus = new ArrayList<>();
        List<SysMenu> sysMenus = super.list();
        List<MenuVO> voList = new ArrayList<>();
        for (SysMenu sysMenu : sysMenus) {
            MenuVO vo = convert2MenVO(sysMenu);
            voList.add(vo);
            if ("-1".equals(sysMenu.getParentId())) {
                topMenus.add(sysMenu);
            }
        }

        Map<String, List<MenuVO>> result = new HashMap<>();
        for (SysMenu sysMenu : topMenus) {
            List<MenuVO> collect = voList.stream()
                    .peek(v -> v.setChildren(getChildren(v, voList)))
                    .sorted(Comparator.comparingInt(SysMenu::getOrderNum))
                    .filter(vo -> vo.getParentId().equals(sysMenu.getId()))
                    .collect(Collectors.toList());
            result.put(sysMenu.getName(), collect);
        }
        return result;
    }

    @Override
    public List<MenuVO> getMenuVoList(String searchParams) {

        List<MenuVO> voList = new ArrayList<>();
        List<SysMenu> sysMenus = sysMenuMapper.selectBySearchParam(searchParams);
        for (SysMenu sysMenu : sysMenus) {
            MenuVO vo = convert2MenVO(sysMenu);
            voList.add(vo);
        }
        boolean hasRoot = voList.stream().anyMatch(vo -> vo.getParentId().equals("-1"));
        if (hasRoot) {
            return voList.stream()
                    .filter(vo -> vo.getParentId().equals("-1"))
                    .peek(v -> {
                        v.setChildren(getChildren(v, voList));
                    })
                    .sorted(Comparator.comparingInt(SysMenu::getOrderNum))
                    .collect(Collectors.toList());
        } else {
            List<String> ids = voList.stream().map(MenuVO::getId).collect(Collectors.toList());
            List<MenuVO> rootList = voList.stream().filter(item -> !ids.contains(item.getParentId())).collect(Collectors.toList());

            for (MenuVO menuVO : rootList) {
                String id = menuVO.getId();
                List<MenuVO> children = voList.stream().filter(vo -> id.equals(vo.getParentId())).collect(Collectors.toList());
                menuVO.setChildren(children);
            }
            return rootList;
        }
    }

    @Override
    public boolean removeByIds(List<String> ids) {
        if (ids.size() == 0) {
            throw new BusinessException("id列表为空!");
        }
        int count = baseMapper.countByParentIds(ids);
        if (count > 0) {
            throw new BusinessException("所选菜单中包含子菜单, 请先删除子菜单!");
        }
        int i = sysMenuMapper.update(new LambdaUpdateWrapper<SysMenu>().eq(SysMenu::getDeleteFlag,DeleteFlagEnum.NO.getCode()).in(SysMenu::getId,ids)
                .set(SysMenu::getUpdateTime, LocalDateTime.now()).set(SysMenu::getUpdateBy,"admin").set(SysMenu::getDeleteFlag,DeleteFlagEnum.YES.getCode()));
        return i > 0;
    }


    @Override
    public List<MenuVO> listByIds(List<String> ids) {
        SystemMenuDTO dto = new SystemMenuDTO();
        dto.setIds(ids);
        return baseMapper.selectBy(dto);
    }


    @Override
    public Map<String, MenuVO> getMenuInfoMap() {
        List<MenuVO> voList = new ArrayList<>();
        List<SysMenu> sysMenus = sysMenuMapper.selectBySearchParam("");
        for (SysMenu sysMenu : sysMenus) {
            MenuVO vo = convert2MenVO(sysMenu);
            voList.add(vo);
        }

        return voList.stream().collect(Collectors.toMap(MenuVO::getPath, m -> m));
    }
}
